#pragma once 

#include <memory>
#include <string>
#include <set>
#include <unordered_map>
#include <mutex>
#include <atomic>
#include <shared_mutex>


namespace mms{
class MediaSink;
class ThreadWorker;
class StreamSession;
class MediaBridge;
class Codec;

class MediaSource : public std::enable_shared_from_this<MediaSource>
{
    friend class MediaSink;
public:
    MediaSource(const std::string &media_type, std::weak_ptr<StreamSession> session, ThreadWorker *worker);

    virtual ~MediaSource();

    virtual bool add_media_sink(std::shared_ptr<MediaSink> media_sink);

    virtual bool remove_media_sink(std::shared_ptr<MediaSink> media_sink);

    virtual std::shared_ptr<MediaBridge> get_or_create_bridge(const std::string& id, StreamSession* session);

    virtual bool remove_bridge(std::shared_ptr<MediaBridge> bridge);

    virtual bool remove_bridge(const std::string& id);

    virtual bool is_no_sinks_for_time(uint32_t milli_sec);

    virtual bool is_ready();


    const std::string& get_media_type() const {
        return media_type_;
    }

    void set_media_type(const std::string& v){
        media_type_ = v;
    }

    std::shared_ptr<StreamSession> get_session();
    void set_session(std::shared_ptr<StreamSession> s);

    void set_source_info(const std::string& domain, const std::string& app_name, const std::string& stream_name);

   

    const std::string& get_domain() const {
        return domain_;
    }

    const std::string& get_app() const {
        return app_name_;
    }

    const std::string& get_stream() const {
        return stream_name_;
    }

    bool has_video() const {
        return has_video_;
    }

    bool has_audio() const {
        return has_audio_;
    }

    virtual void close();

    virtual int64_t get_sinks_count(){
        std::unique_lock<std::recursive_mutex> lck(sinks_mtx_);
        return lazy_sinks_.size();
    }

protected:
    std::atomic_flag closed_ = ATOMIC_FLAG_INIT;
    std::string media_type_; // rtmp rtsp flv
    bool stream_ready_ = false;
    std::weak_ptr<StreamSession> session_;
    ThreadWorker* worker_;
    std::recursive_mutex sinks_mtx_;
    std::set<std::shared_ptr<MediaSink>> lazy_sinks_;

    std::string domain_;
    std::string app_name_;
    std::string stream_name_;

    bool has_video_ = false;
    bool has_audio_ = false;
    std::shared_ptr<Codec> video_codec_;
    std::shared_ptr<Codec> audio_codec_;

    std::shared_mutex bridges_mtx_;
    std::unordered_map<std::string,std::shared_ptr<MediaBridge>> bridges_;
    int64_t last_sinks_or_bridges_leave_time_ = 1;
};
}